﻿using Dispatch.Model;
using Dispatch.Receive;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Dispatch.Utils;

namespace Dispatch.DispatchData
{
    /// <summary>
    /// 传输坞装料信息，只读，使用struct
    /// </summary>
    public struct DeviceMountData
    {
        /// <summary>
        /// 传输坞ID，与传输坞的IP和传输坞编号一一对应
        /// </summary>
        public long DeviceID { get; set; }

        /// <summary>
        /// 传输坞所属的工序
        /// </summary>
        public string Process { get; set; }
        /// <summary>
        /// 出料口数量
        /// </summary>
        public int OutNum { get; set; }

        /// <summary>
        /// 入料口数量
        /// </summary>
        public int InNum { get; set; }
         

        public string MarkerID { get; set; }
    }

    /// <summary>
    /// 最后的指令数据
    /// </summary>
    internal struct DeviceCmd
    {
        public long DeviceID { get; set; }
        public string Cmd { get; set; }   
        public DateTime ReceiveTime { get; set; }
    }

    /// <summary>
    /// 传输坞汇总数据，只读，使用struct
    /// </summary>
    public struct DeviceSynthesisInfo
    {
    
        public long DeviceID { get; set; }
         
        public string Process { get; set; }
 
        public int OutNum { get; set; }
         
        public int InNum { get; set; }
         

        public string Cmd { get; set; } 
        public DateTime? ReceiveTime { get; set; }
        public int AgvID { get; set; }
    }


    /// <summary>
    /// 物料装料数据集合
    /// </summary>
    public class DeviceMountSet
    {
        private static Dictionary<long, DeviceMountData> mountDict = new Dictionary<long, DeviceMountData>();  //装料数据
        private static List<DeviceModel> deviceList = new List<DeviceModel>();   //基础数据 
        private static Dictionary<long,int> agvOfDevice = new Dictionary<long, int>();   //传输坞与AGV对应关系
        private static Dictionary<string,long> deviceOfMarker = new Dictionary<string, long>();  //地标与传输坞对应关系
        private static Dictionary<long, DeviceCmd> cmdDict=new Dictionary<long, DeviceCmd>();  //传输坞收到的最后消息

        #region 初始化数据
        public static void FillBaseData(List<DeviceModel> list )
        {
            lock (deviceList)
            {
                deviceList.Clear();
                deviceList.AddRange(list);

                deviceOfMarker.Clear();
                list.ForEach(item =>
                {
                    deviceOfMarker[item.MarkerID] = item.DeviceID;
                });
            }
        }
      
        public static void FillMountData(List<DeviceMountData> list)
        {
            lock (mountDict)
            {
                mountDict.Clear();
                foreach (DeviceMountData model in list)
                {
                    mountDict[model.DeviceID] = model;
                }
            }
        }

        public static void FillAgv(Dictionary<long, int> dict)
        {
            lock (agvOfDevice)
            {
                agvOfDevice.Clear();
                foreach (var item in dict)
                {
                    agvOfDevice[item.Key] = item.Value;
                }
            }
        }

        #endregion


        /// <summary>
        /// 记录最后的指令，用于监测
        /// </summary>
        /// <param name="DeviceID"></param>
        /// <param name="Data"></param>
        /// <returns></returns>
        internal static Task SaveLog(long DeviceID,DeviceReceiveData Data)
        {
            lock (cmdDict)
            {
                DeviceCmd obj=new DeviceCmd();
                obj.DeviceID = DeviceID;
                obj.ReceiveTime = DateTime.Now;
                obj.Cmd = Data.Cmd.ToString();
                cmdDict[DeviceID] = obj;
            }
            return Task.CompletedTask;
        }



        #region 找传输坞

        /// <summary>
        /// 查找地标对应的传输坞编号
        /// </summary>
        /// <param name="MarkerID"></param>
        /// <returns></returns>
        public static long GetDeviceByMarker(string MarkerID)
        {
            long deviceID = 0;
            if(deviceOfMarker.TryGetValue(MarkerID, out long  id))
            {
                deviceID = id;
            }
            return deviceID;
        }


        /// <summary>
        /// 更新传输坞的物料数量
        /// </summary>
        /// <param name="receiveData"></param>
        /// <returns></returns>
        internal static Task UpdateDeviceMountAsync(long DeviceID, string Process, DeviceReceiveData data)
        {
            lock (mountDict)
            {
                DeviceMountData vo = new DeviceMountData()
                {
                    DeviceID = DeviceID,
                    OutNum = data.OutNum,
                    InNum = data.InNum,
                    Process = Process,
                };
                mountDict[vo.DeviceID] = vo;

                _ = ToMountCacheAsync(vo);
            }

            return Task.CompletedTask;
        }


       
        /// <summary>
        /// 获取最需要传输的传输坞
        /// </summary>
        /// <param name="Process"></param>
        /// <returns></returns>
        public static Task<DeviceModel?> ChooseDevice(string Process)
        {
            long DeviceID = 0;
            lock (mountDict)
            {
                //先找出料最多的。如果出料相同，则找入料最少的
                DeviceID = mountDict.Where(x => x.Value.Process == Process). 
                    OrderByDescending(x => x.Value.OutNum).ThenBy(x=>x.Value.InNum).Select(x=>x.Value.DeviceID).FirstOrDefault(); 
            }
            if (DeviceID == 0)
            {
                return Task.FromResult<DeviceModel?>(null);
            }
            DeviceModel? ext = null;
            var obj = deviceList.Find(x => x.DeviceID == DeviceID);
            if (obj != null)
            {
                ext = Tools.Copy(obj);
            }
            return Task.FromResult<DeviceModel?>(null);
        }

        /// <summary>
        /// 通过IP和坞编号查找传输坞
        /// </summary>
        /// <param name="IP"></param>
        /// <param name="DockNum"></param>
        /// <returns></returns>
        public static  DeviceModel?  GetDevice(string IP, int DockNum)
        {
            DeviceModel? device = null;
            var obj = deviceList.Where(x => x.IP == IP && x.DockNum == DockNum).FirstOrDefault();
            if (obj != null)
            {
                device = Tools.Copy(obj);
            }
            return device;
        }

        /// <summary>
        /// 通过IP查找传输坞的解析标识
        /// </summary>
        /// <param name="IP"></param>
        /// <returns></returns>
        public static string? GetDeviceType(string IP)
        {
            var obj = deviceList.Where(x => x.IP == IP).Select(x=>x.DeviceType).FirstOrDefault();
            return obj;
        }

        /// <summary>
        /// 通过ID找到具体的传输坞
        /// </summary>
        /// <param name="DeviceID"></param>
        /// <returns></returns>
        public static DeviceModel? GetDevice(long DeviceID)
        {
            DeviceModel? device = null;
            var obj = deviceList.Where(x => x.DeviceID  == DeviceID).FirstOrDefault();
            if (obj != null)
            {
                device = Tools.Copy(obj);
            }
            return null;
        }

          
        #endregion


        #region agv与传输坞的关系

        /// <summary>
        /// 更新传输坞前的AGV，用于监测
        /// </summary>
        /// <param name="DeviceID"></param>
        /// <param name="AgvID"></param>
        /// <returns></returns>
        public static Task BindAgvAsync(long DeviceID,int AgvID)
        {
            lock (agvOfDevice)
            {
                List<long> key = new List<long>(); 
                foreach(var (k,v) in agvOfDevice)
                {
                    if (v == AgvID)
                    {
                        key.Add(k);
                    }
                }
                agvOfDevice[DeviceID] = AgvID;
                _ = ToBindCacheAsync(DeviceID, AgvID);
                 
                if (key.Count > 0)
                { 
                    key.ForEach(item => agvOfDevice[DeviceID] = 0);
                    _=ToBindCacheAsync(key);
                }
            }
            return Task.CompletedTask;
        }

        /// <summary>
        /// 查询停靠在传输坞的AGV
        /// </summary>
        /// <param name="DeviceID"></param>
        /// <returns></returns>
        public static Task<int> GetAgv(long DeviceID)
        {
            int AgvID=0;
            if(agvOfDevice.TryGetValue(DeviceID, out int id))
            {
                AgvID = id;
            }
            return Task.FromResult(AgvID);
        }

        #endregion


        #region 读取数据


        /// <summary>
        /// 监控用，获取所有传输坞的信息、物料状态、最后的指令
        /// </summary>
        /// <returns></returns>
        public static Task<List<DeviceSynthesisInfo>> GetAllInfoAsync()
        {
            List<DeviceSynthesisInfo> list = new List<DeviceSynthesisInfo>();
            deviceList.ForEach(item =>
            {
                DeviceSynthesisInfo obj = new DeviceSynthesisInfo();
                obj.Process = item.Process;
                obj.DeviceID = item.DeviceID;

                //装料情况+
                if (mountDict.TryGetValue(item.DeviceID, out DeviceMountData mount))
                {
                    obj.OutNum = mount.OutNum;
                    obj.InNum = mount.InNum;
                }


                //指令
                if (cmdDict.TryGetValue(item.DeviceID, out DeviceCmd cmd))
                {
                    obj.Cmd = cmd.Cmd;
                    obj.ReceiveTime = cmd.ReceiveTime;
                }

                //绑定的agv
                if (agvOfDevice.TryGetValue(item.DeviceID, out int id))
                {
                    obj.AgvID = id;
                }
                list.Add(obj);
            });

            return Task.FromResult(list);
        }

        #endregion


        #region 写缓存

        static Task ToMountCacheAsync(DeviceMountData obj)
        {
            return Task.CompletedTask;
        }

        static Task ToBindCacheAsync(long DeviceID,int AgvID)
        {
            return Task.CompletedTask;
        }

        static Task ToBindCacheAsync(List<long> ids)
        {
            return Task.CompletedTask;
        }
        
        #endregion
    }


    /// <summary>
    /// 传输坞工厂，根据解析标识构造对应的解析类（实现了IDeviceEvent的类） 
    /// </summary>
    internal class DeviceFactory
    {
        public static IDeviceEvent? GetDevice(string DeviceType)
        {

            IDeviceEvent? abs = DeviceType switch
            {
                "Demo" => new DemoDevice(),
                _ => null,
            };
            return abs;
        }
    }
}
